//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package org_dao

import (
	"context"
	"regexp"

	"atomgit.com/openlinksaas/api-server/dao/db_ns"
	"atomgit.com/openlinksaas/proto-gen-go.git/org_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type BasicOrgInfoDbItem struct {
	OrgName string `bson:"orgName"`
	OrgDesc string `bson:"orgDesc"`
}

type SettingDbItem struct {
	EnableDayReport bool `bson:"enableDayReport"`
	EnbleWeekReport bool `bson:"enbleWeekReport"`
	EnableOkr       bool `bson:"enableOkr"`
	EnableAsset     bool `bson:"enableAsset"`
	EnableEvaluate  bool `bson:"enableEvaluate"`
}

type OrgInfoDbItem struct {
	OrgId                 string             `bson:"_id"`
	BasicInfo             BasicOrgInfoDbItem `bson:"basicInfo"`
	CreateTime            int64              `bson:"createTime"`
	UpdateTime            int64              `bson:"updateTime"`
	OwnerUserId           string             `bson:"ownerUserId"`
	NewMemberDepartMentId string             `bson:"newMemberDepartMentId"`
	Setting               SettingDbItem      `bson:"setting"`

	DepartMentCount uint32 `bson:"departMentCount"`
	MemberCount     uint32 `bson:"memberCount"`
}

func (item *OrgInfoDbItem) ToOrgInfo() *org_api.OrgInfo {
	return &org_api.OrgInfo{
		OrgId: item.OrgId,
		BasicInfo: &org_api.BasicOrgInfo{
			OrgName: item.BasicInfo.OrgName,
			OrgDesc: item.BasicInfo.OrgDesc,
		},
		CreateTime:            item.CreateTime,
		UpdateTime:            item.UpdateTime,
		OwnerUserId:           item.OwnerUserId,
		NewMemberDepartMentId: item.NewMemberDepartMentId,
		DepartMentCount:       item.DepartMentCount,
		MemberCount:           item.MemberCount,
		Setting: &org_api.Setting{
			EnableDayReport: item.Setting.EnableDayReport,
			EnbleWeekReport: item.Setting.EnbleWeekReport,
			EnableOkr:       item.Setting.EnableOkr,
			EnableAsset:     item.Setting.EnableAsset,
			EnableEvaluate:  item.Setting.EnableEvaluate,
		},
	}
}

type _OrgInfoDao struct {
	mc *mongo.Collection
}

func newOrgInfoDao(db *mongo.Database) (*_OrgInfoDao, error) {
	mc := db.Collection(db_ns.DB_NS_ORG + "info")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"updateTime", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_OrgInfoDao{mc: mc}, nil
}

func (db *_OrgInfoDao) Insert(ctx context.Context, dbItem *OrgInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_OrgInfoDao) Exist(ctx context.Context, orgId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": orgId})
	return count > 0, err
}

func (db *_OrgInfoDao) Get(ctx context.Context, orgId string) (*OrgInfoDbItem, error) {
	retItem := &OrgInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": orgId}).Decode(retItem)
	return retItem, err
}

func (db *_OrgInfoDao) Remove(ctx context.Context, orgId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": orgId})
	return err
}

func (db *_OrgInfoDao) Update(ctx context.Context, orgId string, dbItem *BasicOrgInfoDbItem, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": orgId}, bson.M{"$set": bson.M{"basicInfo": dbItem, "updateTime": updateTime}})
	return err
}

func (db *_OrgInfoDao) UpdateSetting(ctx context.Context, orgId string, dbItem *SettingDbItem, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": orgId}, bson.M{"$set": bson.M{"setting": dbItem, "updateTime": updateTime}})
	return err
}

func (db *_OrgInfoDao) UpdateDepartMentCount(ctx context.Context, orgId string, count uint32) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": orgId}, bson.M{"$set": bson.M{"departMentCount": count}})
	return err
}

func (db *_OrgInfoDao) UpdateMemberCount(ctx context.Context, orgId string, count uint32) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": orgId}, bson.M{"$set": bson.M{"memberCount": count}})
	return err
}

func (db *_OrgInfoDao) UpdateOwner(ctx context.Context, orgId, ownerUserId string, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": orgId}, bson.M{"$set": bson.M{"ownerUserId": ownerUserId, "updateTime": updateTime}})
	return err
}

func (db *_OrgInfoDao) ListById(ctx context.Context, orgIdList []string) ([]*OrgInfoDbItem, error) {
	if len(orgIdList) == 0 {
		return []*OrgInfoDbItem{}, nil
	}
	cursor, err := db.mc.Find(ctx, bson.M{"_id": bson.M{"$in": orgIdList}}, options.Find().SetSort(bson.M{"createTime": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*OrgInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_OrgInfoDao) Count(ctx context.Context, filterByKeyword bool, keyword string, filterByOrg bool, orgIdList []string) (uint32, error) {
	query := bson.M{}
	if filterByKeyword {
		query["basicInfo.orgName"] = primitive.Regex{
			Pattern: regexp.QuoteMeta(keyword),
			Options: "i",
		}
	}
	if filterByOrg {
		query["_id"] = bson.M{"$in": orgIdList}
		if len(orgIdList) == 0 {
			return 0, nil
		}
	}
	count, err := db.mc.CountDocuments(ctx, query)
	return uint32(count), err
}

func (db *_OrgInfoDao) List(ctx context.Context, filterByKeyword bool, keyword string, filterByOrg bool, orgIdList []string, offset, limit int64) ([]*OrgInfoDbItem, error) {
	query := bson.M{}
	if filterByKeyword {
		query["basicInfo.orgName"] = primitive.Regex{
			Pattern: regexp.QuoteMeta(keyword),
			Options: "i",
		}
	}
	if filterByOrg {
		query["_id"] = bson.M{"$in": orgIdList}
		if len(orgIdList) == 0 {
			return []*OrgInfoDbItem{}, nil
		}
	}
	cursor, err := db.mc.Find(ctx, query, options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.M{"updateTime": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*OrgInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}
